﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Threading;
using ScrumTable.Common.Logging;

#endregion

namespace ScrumTable.Common.Threading
{
    /// <summary>
    /// Executes a call in a new separate thread context.
    /// </summary>
    /// <typeparam name="TData">Object which will be provided by the call.</typeparam>
    public class AsyncCall<TData> : ICall<TData>
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private volatile Action<TData> _toCall;

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets/sets the action to execute asynchrnously.
        /// </summary>
        protected Action<TData> ToCall
        {
            get { return _toCall; }
            set { _toCall = value; }
        }

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new AsyncCall instance and consumes the function to
        /// execute.
        /// </summary>
        public AsyncCall(Action<TData> toCall)
        {
            PreCondition.AssertNotNull(toCall, "toCall");

            ToCall = toCall;
        }

        /// <summary>
        /// Empty constructor needed for derived AsyncCall class.
        /// </summary>
        protected AsyncCall()
        {
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Executes the item.
        /// </summary>
        /// <param name="data">Contains the data which is required to execute the item.</param>
        public void Execute(TData data)
        {
            Thread newThread = new Thread(StartAsync);
            newThread.Name = GetType().Name;
            newThread.Start(data);
        }

        /// <summary>
        /// Executes the item.
        /// </summary>
        public void Execute()
        {
            Execute(default(TData));
        }

        private void StartAsync(object data)
        {
            using (Logger<AsyncCall<TData>>.StartNdc(Thread.CurrentThread.Name))
            {
                try
                {
                    ToCall((TData)data);
                }
                catch (Exception e)
                {
                    Logger<AsyncCall<TData>>.Error(e.Message, e);
                    throw;
                }
                
            }
        }

        #endregion
    }

    /// <summary>
    /// Executes a call in a new separate thread context.
    /// </summary>
    public class AsyncCall : AsyncCall<object>
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private readonly Action _toCallWithoutArgs;

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new AsyncCall instance and consumes the function to
        /// execute.
        /// </summary>
        public AsyncCall(Action toCall)
        {
            PreCondition.AssertNotNull(toCall, "toCall");

            _toCallWithoutArgs = toCall;
            ToCall = StartAsyncWithoutArgs;
        }

        #endregion


        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        private void StartAsyncWithoutArgs(object data)
        {
            _toCallWithoutArgs();
        }

        #endregion
    }
}
